package com.xxx.config;

import com.alibaba.cola.statemachine.Action;
import com.alibaba.cola.statemachine.Condition;
import com.alibaba.cola.statemachine.StateMachine;
import com.alibaba.cola.statemachine.builder.StateMachineBuilder;
import com.alibaba.cola.statemachine.builder.StateMachineBuilderFactory;
import com.xxx.pojo.enums.ApplyStatusEnum;
import com.xxx.pojo.enums.Event;
import com.xxx.pojo.LeaveContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 状态机注册和初始化
 */
@Configuration
public class StateMachineRegist {

    private static final Logger logger = LoggerFactory.getLogger(StateMachineRegist.class);

    // COLA会将该状态机在StateMachineFactory类中，放入一个ConcurrentHashMap，以状态机名为key注册。
    private final String STATE_MACHINE_ID = "leaveStateMachineId";  // 状态机id

    /**
     * 构建状态机实例
     */
    @Bean
    public StateMachine<ApplyStatusEnum, Event, LeaveContext> stateMachine() {
        // 创建状态机实例
        StateMachineBuilder<ApplyStatusEnum, Event, LeaveContext> stateMachineBuilder = StateMachineBuilderFactory.create();

        // 状态机流转规则1：员工请假触发事件（因为没有源状态，初始化时只是同一个状态流转，所以用内部流转）
        stateMachineBuilder
                .internalTransition()   // 内部流转
                .within(ApplyStatusEnum.LEAVE_SUBMIT)   // 同一个状态之间流转
                .on(Event.EMPLOYEE_SUBMIT)   // 事件
                .perform(doAction());   // 执行动作

        // 状态机流转规则2：部门主管审批触发事件（依赖上一个状态：LEAVE_SUBMIT），分别为通过和不通过两种状态流转
        // 定义审批通过状态流转
        stateMachineBuilder.externalTransition()   // 外部流转
                .from(ApplyStatusEnum.LEAVE_SUBMIT)  // 流转前状态，只有调用了from()方法，才能调用to()方法
                .to(ApplyStatusEnum.LEADE_AUDIT_PASS)  // 流转后状态，只有调用了to()方法，才能调用on()方法
                .on(Event.DIRECTLEADER_AUDIT) // 事件
                .when(checkIfPass())    // 流转条件
                .perform(doAction());   // 执行动作
        // 定义审批不通过状态流转
        stateMachineBuilder
                .externalTransition()   // 外部流转
                .from(ApplyStatusEnum.LEAVE_SUBMIT) // 流转前状态
                .to(ApplyStatusEnum.LEADE_AUDIT_REFUSE) // 流转后状态
                .on(Event.DIRECTLEADER_AUDIT)   // 事件
                .when(checkIfNotPass())  // 条件
                .perform(doAction());    // 动作

        // 状态机流转规则3：hr事件触发(依赖上一个状态:LEADE_AUDIT_PASS)
        stateMachineBuilder.externalTransition().from(ApplyStatusEnum.LEADE_AUDIT_PASS).to(ApplyStatusEnum.HR_PASS).on(Event.HR_AUDIT).when(checkIfPass()).perform(doAction());
        stateMachineBuilder.externalTransition().from(ApplyStatusEnum.LEADE_AUDIT_PASS).to(ApplyStatusEnum.HR_REFUSE).on(Event.HR_AUDIT).when(checkIfNotPass()).perform(doAction());

        // 返回状态机实例（带有状态机id）
        return stateMachineBuilder.build(STATE_MACHINE_ID);
    }

    /**
     * 状态机流转满足条件
     */
    private Condition<LeaveContext> checkIfPass() {
        return (ctx) -> ctx.getIdea().equals(0);
    }

    /**
     * 状态机流转不满足条件
     */
    private Condition<LeaveContext> checkIfNotPass() {
        return (ctx) -> ctx.getIdea().equals(1);
    }

    /**
     * 事件触发后，匹配成功对应的条件后，就会执行具体动作
     * 可以自定义完成具体业务逻辑...
     */
    private Action<ApplyStatusEnum, Event, LeaveContext> doAction() {
        return (from, to, event, ctx) -> {
            logger.info("from:" + from + " to:" + to + " on:" + event + " condition:" + ctx);
        };
    }

}
